# -*- coding: utf-8 -*-
"""
Created on Tue Jan 22 13:09:33 2013

@author: Winand
"""

from __future__ import with_statement
from webapi.interlocks import InterProcessLock, SingleInstanceError
if __name__ == '__main__':
    ipl = InterProcessLock("server_lock_lock")
    try:
        ipl.lock()
    except SingleInstanceError:
        exit() #duplicate, quit
    
from webapi.server.socketpipe import SocketPipe
import sys, subprocess, tempfile, os #, time
from settings import SHARED_SERVER_ADDR, SHARED_SERVER_PORT, LOG_TO_CONSOLE
ANSWER_OK = 1
FILE_FLAG = os.path.join(tempfile.gettempdir(), "lancomm_server_starting")

if __name__ != '__main__':
    def init_server(): #start server
        try:
            #on Windows, if close_fds is true then no handles will be inherited
            #by the child process. Note that on Windows, you cannot set close_fds
            #to true and also redirect the standard handles by setting stdin, stdout or stderr.
            subprocess.Popen([sys.executable, __file__], close_fds=True, \
                creationflags=subprocess.CREATE_NEW_CONSOLE if LOG_TO_CONSOLE else 0)
        except Exception, e:
            error("Failed to start main server", e)
            
    def try_conn():
        sockpipe=SocketPipe()
        try:
            sockpipe.connect(SHARED_SERVER_ADDR, SHARED_SERVER_PORT, timeout=0.3)
            rcv = sockpipe.send(("test",))
            if rcv == ANSWER_OK: return True
        except: pass
        finally: sockpipe.close()

else:
    
    from webapi.log import InitLocalLogging
    InitLocalLogging() #server collects log
    from webapi.log import debug, error

    ############
    
    #server test, returns ANSWER_OK to client
    def test(data_pipe, *args):
        data_pipe.send_data(ANSWER_OK)
        
    from settings import SERVICELIST #list of available services
    callbacks = {}
    
    def srv_clbk(data_pipe, mod, d_args):
        data_pipe.send_data(ANSWER_OK) #ok. request will be processed
        global callbacks
        if not mod in callbacks:
            if mod in SERVICELIST:
                callbacks[mod] = __import__("services."+mod+".callback", fromlist="callback")
            else: error("srv_clbk: unknown module requested", mod)
        callbacks[mod].background_callback(**d_args)
    
    #import handlers
    import webapi.server.remotedict as remotedict
    from webapi.log import remoteLogHandler
    
    #server is asked to shutdown (see check_requests())
    def kill_event(data_pipe):
        server.shutdown()
    
    #request handlers
    HDLRS = {
        "dictionary": remotedict.dictionary,
        "test": test,
        "srv_callback": srv_clbk,
        "log": remoteLogHandler,
        "kill": kill_event,
    }
    
    ############
    
    #monitor requests and exit to save resources
    any_requests = False
    from settings import SERVER_SHUTDOWN_TIMEOUT
    from threading import Timer

    def check_requests():
        global any_requests
        if not any_requests:
            sockpipe=SocketPipe()
            try:
                sockpipe.connect(SHARED_SERVER_ADDR, SHARED_SERVER_PORT, timeout=0.3)
                sockpipe.send_data(("kill",))
            except: pass
            finally: sockpipe.close()
        else:
            any_requests = False            
            newTimer(SERVER_SHUTDOWN_TIMEOUT) #restart timer
        
    def newTimer(sec):
        global timer
        timer = Timer(sec, check_requests)
        timer.start()
        
    timer = None
    newTimer(SERVER_SHUTDOWN_TIMEOUT) #start monitor

    ############
    
    import SocketServer
    class BackgroundReqHandler(SocketServer.BaseRequestHandler, SocketPipe):
        def route(self, path, *args):
            handler = HDLRS.get(path, None)
            if handler: handler(self, *args)
            else: error("server handler", path, "not found")
    
        def handle(self):
#            debug("new req")
            global any_requests
            any_requests = True
            self.route(*self.recv_data())
    
    #Reuse a local socket in TIME_WAIT state, without waiting for its timeout to expire
    class BackgroundServer(SocketServer.ThreadingTCPServer):
        allow_reuse_address = True
    server = BackgroundServer((SHARED_SERVER_ADDR, SHARED_SERVER_PORT), \
                                                        BackgroundReqHandler)
    debug("start listening...")
    server.serve_forever()
    remotedict.flush_and_stop_monitor() #save data to disk before exit
    timer.cancel() #It's unnecessary usually, cause timer thread itself makes a decision to shutdown
